<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<meta name="robots" content="noindex">
	<title>io-fx09 - iowen.cn</title>
    <style>
    * {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}

body {
	background-color: #000;
	overflow: hidden;
}

#holder {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	overflow: hidden;
}
    </style>
</head>
<body>
  <div id="holder"></div>
  
    <script>  
     (function() {
	var pi = Math.PI;
	var pi2 = 2 * Math.PI;
	this.Waves = function(holder, options) {
		var Waves = this;
		Waves.options = extend(options || {}, {
			resize: false,
			rotation: 45,
			waves: 5,
			width: 100,
			hue: [11, 14],
			amplitude: 0.5,
			background: true,
			preload: true,
			speed: [0.004, 0.008],
			debug: false,
			fps: false,
		});
		Waves.waves = [];
		Waves.holder = document.querySelector(holder);
		Waves.canvas = document.createElement('canvas');
		Waves.ctx = Waves.canvas.getContext('2d');
		Waves.holder.appendChild(Waves.canvas);
		Waves.hue = Waves.options.hue[0];
		Waves.hueFw = true;
		Waves.stats = new Stats();
		Waves.resize();
		Waves.init(Waves.options.preload);
		if (Waves.options.resize) window.addEventListener('resize', function() {
			Waves.resize();
		}, false);
	};
	Waves.prototype.init = function(preload) {
		var Waves = this;
		var options = Waves.options;
		for (var i = 0; i < options.waves; i++) Waves.waves[i] = new Wave(Waves);
		if (preload) Waves.preload();
	};
	Waves.prototype.preload = function() {
		var Waves = this;
		var options = Waves.options;
		for (var i = 0; i < options.waves; i++) {
			Waves.updateColor();
			for (var j = 0; j < options.width; j++) {
				Waves.waves[i].update();
			}
		}
	};
	Waves.prototype.render = function() {
		var Waves = this;
		var ctx = Waves.ctx;
		var options = Waves.options;
		Waves.updateColor();
		Waves.clear();
		if (Waves.options.debug) {
			ctx.beginPath();
			ctx.strokeStyle = '#f00';
			ctx.arc(Waves.centerX, Waves.centerY, Waves.radius, 0, pi2);
			ctx.stroke();
		}
		if (Waves.options.background) {
			Waves.background();
		}
		each(Waves.waves, function(wave, i) {
			wave.update();
			wave.draw();
		});
	};
	Waves.prototype.animate = function() {
		var Waves = this;
		Waves.render();
		if (Waves.options.fps) {
			Waves.stats.log();
			Waves.ctx.font = '12px Arial';
			Waves.ctx.fillStyle = '#fff';
			Waves.ctx.fillText(Waves.stats.fps() + ' FPS', 10, 22);
		}
		window.requestAnimationFrame(Waves.animate.bind(Waves));
	};
	Waves.prototype.clear = function() {
		var Waves = this;
		Waves.ctx.clearRect(0, 0, Waves.width, Waves.height);
	};
	Waves.prototype.background = function() {
		var Waves = this;
		var ctx = Waves.ctx;
		var gradient = Waves.ctx.createLinearGradient(0, 0, 0, Waves.height);
		gradient.addColorStop(0, '#000');
		gradient.addColorStop(1, Waves.color);
		ctx.fillStyle = gradient;
		ctx.fillRect(0, 0, Waves.width, Waves.height);
	};
	Waves.prototype.resize = function() {
		var Waves = this;
		var width = Waves.holder.offsetWidth;
		var height = Waves.holder.offsetHeight;
		Waves.scale = window.devicePixelRatio || 1;
		Waves.width = width * Waves.scale;
		Waves.height = height * Waves.scale;
		Waves.canvas.width = Waves.width;
		Waves.canvas.height = Waves.height;
		Waves.canvas.style.width = width + 'px';
		Waves.canvas.style.height = height + 'px';
		Waves.radius = Math.sqrt(Math.pow(Waves.width, 2) + Math.pow(Waves.height, 2)) / 2;
		Waves.centerX = Waves.width / 2;
		Waves.centerY = Waves.height / 2;
		//Waves.radius /= 2; // REMOVE FOR FULLSREEN
	};
	Waves.prototype.updateColor = function() {
		var Waves = this;
		Waves.hue += (Waves.hueFw) ? 0.01 : -0.01;
		if (Waves.hue > Waves.options.hue[1] && Waves.hueFw) {
			Waves.hue = Waves.options.hue[1];
			Waves.Waves = false;
		} else if (Waves.hue < Waves.options.hue[0] && !Waves.hueFw) {
			Waves.hue = Waves.options.hue[0];
			Waves.Waves = true;
		}
		var a = Math.floor(127 * Math.sin(0.3 * Waves.hue + 0) + 128);
		var b = Math.floor(127 * Math.sin(0.3 * Waves.hue + 2) + 128);
		var c = Math.floor(127 * Math.sin(0.3 * Waves.hue + 4) + 128);
		Waves.color = 'rgba(' + a + ',' + b + ',' + c + ', 0.1)';
	};

	function Wave(Waves) {
		var Wave = this;
		var speed = Waves.options.speed;
		Wave.Waves = Waves;
		Wave.Lines = [];
		Wave.angle = [
			rnd(pi2),
			rnd(pi2),
			rnd(pi2),
			rnd(pi2)
		];
		Wave.speed = [
			rnd(speed[0], speed[1]) * rnd_sign(),
			rnd(speed[0], speed[1]) * rnd_sign(),
			rnd(speed[0], speed[1]) * rnd_sign(),
			rnd(speed[0], speed[1]) * rnd_sign(),
		];
		return Wave;
	}
	Wave.prototype.update = function() {
		var Wave = this;
		var Lines = Wave.Lines;
		var color = Wave.Waves.color;
		Lines.push(new Line(Wave, color));
		if (Lines.length > Wave.Waves.options.width) {
			Lines.shift();
		}
	};
	Wave.prototype.draw = function() {
		var Wave = this;
		var Waves = Wave.Waves;
		var ctx = Waves.ctx;
		var radius = Waves.radius;
		var radius3 = radius / 3;
		var x = Waves.centerX;
		var y = Waves.centerY;
		var rotation = dtr(Waves.options.rotation);
		var amplitude = Waves.options.amplitude;
		var debug = Waves.options.debug;
		var Lines = Wave.Lines;
		each(Lines, function(line, i) {
			if (debug && i > 0) return;
			var angle = line.angle;
			var x1 = x - radius * Math.cos(angle[0] * amplitude + rotation);
			var y1 = y - radius * Math.sin(angle[0] * amplitude + rotation);
			var x2 = x + radius * Math.cos(angle[3] * amplitude + rotation);
			var y2 = y + radius * Math.sin(angle[3] * amplitude + rotation);
			var cpx1 = x - radius3 * Math.cos(angle[1] * amplitude * 2);
			var cpy1 = y - radius3 * Math.sin(angle[1] * amplitude * 2);
			var cpx2 = x + radius3 * Math.cos(angle[2] * amplitude * 2);
			var cpy2 = y + radius3 * Math.sin(angle[2] * amplitude * 2);
			ctx.strokeStyle = (debug) ? '#fff' : line.color;
			ctx.beginPath();
			ctx.moveTo(x1, y1);
			ctx.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x2, y2);
			ctx.stroke();
			if (debug) {
				ctx.strokeStyle = '#fff';
				ctx.globalAlpha = 0.3;
				ctx.beginPath();
				ctx.moveTo(x1, y1);
				ctx.lineTo(cpx1, cpy1);
				ctx.stroke();
				ctx.beginPath();
				ctx.moveTo(x2, y2);
				ctx.lineTo(cpx2, cpy2);
				ctx.stroke();
				ctx.globalAlpha = 1;
			}
		});
	};

	function Line(Wave, color) {
		var Line = this;
		var angle = Wave.angle;
		var speed = Wave.speed;
		Line.angle = [
			Math.sin(angle[0] += speed[0]),
			Math.sin(angle[1] += speed[1]),
			Math.sin(angle[2] += speed[2]),
			Math.sin(angle[3] += speed[3])
		];
		Line.color = color;
	}

	function Stats() {
		this.data = [];
	}
	Stats.prototype.time = function() {
		return (performance || Date).now();
	};
	Stats.prototype.log = function() {
		if (!this.last) {
			this.last = this.time();
			return 0;
		}
		this.new = this.time();
		this.delta = this.new - this.last;
		this.last = this.new;
		this.data.push(this.delta);
		if (this.data.length > 10) this.data.shift();
	};
	Stats.prototype.fps = function() {
		var fps = 0;
		each(this.data, function(data, i) {
			fps += data;
		});
		return Math.round(1000 / (fps / this.data.length));
	};

	function each(items, callback) {
		for (var i = 0; i < items.length; i++) {
			callback(items[i], i);
		}
	}

	function extend(options, defaults) {
		for (var key in options)
			if (defaults.hasOwnProperty(key)) defaults[key] = options[key];
		return defaults;
	}

	function dtr(deg) {
		return deg * pi / 180;
	}

	function rtd(rad) {
		return rad * 180 / pi;
	}

	function diagonal_angle(w, h) {
		var a = Math.atan2(h, w) * 1.27325;
		return a;
	}

	function rnd(a, b) {
		if (arguments.length == 1) return Math.random() * a;
		return a + Math.random() * (b - a);
	}

	function rnd_sign() {
		return (Math.random() > 0.5) ? 1 : -1;
	}
})();
var waves = new Waves('#holder', {
	fps: false,
	waves: 3,
	width: 200,
});
waves.animate();
    </script>
</body>
</html>